﻿using ExcelDataReader;
using Heroius.Extension;
using Heroius.Extension.WPF;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Diagnostics;
using Heroius.Extension.Desktop.Utility;
using Heroius.Extension.Desktop;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Heroius.Files;

namespace Heroius.NeuTabDiffPeriods
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();

            TbVer.Text = $"Ver: {Assembly.GetExecutingAssembly().GetName().Version.ToString(4)}, Powered by Heroius-Extension, 专属定制：东北大学教务处";

            var logpath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\\Heroius\\NeuTabDiffPeriods\\logs\\{DateTime.Now:yyyyMMdd}.log";
            configpath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\\Heroius\\NeuTabDiffPeriods\\config.xml";
            PathHelper.CreateDirectory(logpath);
            Logger = new TextLogger(logpath);

            silo = new EntitySilo();
            Config = new Config();
            if (File.Exists(configpath))
            {
                silo.Load(configpath);
                silo.Fetch("default", Config);
            }

            OpenDia = new OpenFileDialog()
            {
                Filter = "Excel文件|*.xlsx|Excel文件（旧格式）|*.xls"
            };

            ExBar.AddButton("打开开课情况表", "/Heroius.NeuTabDiffPeriods;Component/img/bopen.png", this, "OpenBasicTab");
            ExBar.AddButton("打开多教师开课表", "/Heroius.NeuTabDiffPeriods;Component/img/copen.png", this, "OpenCollegeTab");
            ExBar.AddButton("执行课时核查", "/Heroius.NeuTabDiffPeriods;Component/img/play.png", this, "ExcuteDiff");
            ExBar.AddButton("参数设置", "/Heroius.NeuTabDiffPeriods;Component/img/config.png", this, "EditConfig");
            ExBar.AddButton("帮助", "/Heroius.NeuTabDiffPeriods;Component/img/help.png", this, "Help");

            BasicRecords = new RecordCollection();
            CollegeRecords = new RecordCollection();
            LackRecords = new RecordCollection();

            DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public ObservableCollection<ExToolBar.IconButtonInfo> ExButtons { get; set; }
        public RecordCollection BasicRecords { get; set; }
        public RecordCollection CollegeRecords { get; set; }
        public RecordCollection LackRecords { get; set; }

        public OpenFileDialog OpenDia;
        public TextLogger Logger;
        public Config Config { get; set; }
        EntitySilo silo;
        string configpath;

        public bool Loaded_Basic = false, Loaded_College = false;

        public void OpenBasicTab()
        {
            OpenTabTo(BasicRecords, DgBasic, TcBasic, ref Loaded_Basic);
        }

        public void OpenCollegeTab()
        {
            OpenTabTo(CollegeRecords, DgCollege, TcCollege, ref Loaded_College);
        }

        void OpenTabTo(RecordCollection target, DataGrid dg, TextBlock tb, ref bool mark)
        {
            try
            {
                if (OpenDia.ShowDialog() == true)
                {
#if DEBUG

                    DateTime __d1, __d2;
#endif
                    mark = false;
                    using (Stream stream = OpenDia.OpenFile())
                    {
                        var reader = ExcelReaderFactory.CreateReader(stream);
#if DEBUG
                        Logger.Write($"EDR recs cnt:{reader.RowCount}");
                        __d1 = DateTime.Now;
#endif
                        if (reader.Read())
                        {
                            int fieldc = reader.FieldCount;
                            List<string> header = new List<string>();
                            for (int i = 0; i < fieldc; i++)
                            {
                                string cv = reader.GetString(i).Trim();
                                if (string.IsNullOrWhiteSpace(cv))
                                {
                                    fieldc = i;
                                    break;
                                }
                                else
                                {
                                    header.Add(cv);
                                }
                            }

                            target.DefineExtProps(header.ToArray());

                            while (reader.Read())
                            {
                                if (reader.GetValue(0) == null)
                                    break;
                                string[] cells = new string[fieldc];

                                for (int i = 0; i < fieldc; i++)
                                {
                                    cells[i] = reader.GetValue(i).As("").Trim();
                                }
                                target.Add(cells);
                            }
                        }
#if DEBUG
                        __d2 = DateTime.Now;
                        Logger.Write($"EDR read during: {(__d2 - __d1).TotalMilliseconds} ms");
#endif
                        reader.Close();
                    }
                    target.UpdateDg(dg, tb);
                    mark = true;
#if DEBUG
                    Logger.Write($"DataGrid during: {(DateTime.Now - __d2).TotalMilliseconds} ms");
#endif

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Logger.Write($"Err on Open:{ex.Message}");
            }
        }

        public void ExcuteDiff()
        {
            try
            {
                if (Loaded_Basic && Loaded_College)
                {
                    //开课表：开课号，课程名称，学时，授课教师，授课教师工号
                    var bci = GetColIndex(BasicRecords, Config.B_LessonID);
                    var bni = GetColIndex(BasicRecords, Config.B_LessonName);
                    var bpi = GetColIndex(BasicRecords, Config.B_Periods);
                    var bti = GetColIndex(BasicRecords, Config.B_Teachers);
                    var bii = GetColIndex(BasicRecords, Config.B_TeacherIDs);

                    //多人表：开课号，课程名称，总学时，授课教师，教师授课学时，授课教师工号
                    var cci = GetColIndex(CollegeRecords, Config.C_LessonID);
                    var cni = GetColIndex(CollegeRecords, Config.C_LessonName);
                    var cpi = GetColIndex(CollegeRecords, Config.C_Periods);
                    var cti = GetColIndex(CollegeRecords, Config.C_Teacher);
                    var ctpi = GetColIndex(CollegeRecords, Config.C_TeacherPeriods);
                    var cii = GetColIndex(CollegeRecords, Config.C_TeacherIDs);

                    //不一致详情
                    string[] inc = new string[] {
                        "多教师开课表 中缺少此开课号的记录",
                        "两表中相同开课号的记录，存在 课程名称不一致",
                        "两表中相同开课号的记录，存在 学时/总学时不一致",
                        "两表中相同开课号的记录，授课教师姓名不一致",
                        "教师授课学时总和与总学时不想等",
                        "非多人授课课程被误报在 多教师开课表 中",
                        "两表中相同开课号的记录，授课教师工号不一致"
                    };

                    LackRecords.DefineExtProps("开课号", "课程名称", "不一致详情");

                    foreach (var r in BasicRecords.PropValues)
                    {
                        var bc = r[bci];
                        var bn = r[bni];
                        var selected = CollegeRecords.PropValues.Where(rec => rec[cci] == bc);
                        if (selected.Count() == 0)
                        {
                            if (Config.Check_01_MultiLackLesson)
                            {
                                LackRecords.Add(bc, bn, inc[0]);
                            }
                            continue;
                        }

                        double bp = r[bpi].As<double>();
                        var bts = r[bti].Split(new string[] { Config.NameSeperator }, StringSplitOptions.RemoveEmptyEntries).Select(str => str.Trim()).ToList();
                        var bis = r[bii].Split(new string[] { Config.IdSeperator }, StringSplitOptions.RemoveEmptyEntries).Select(str => str.Trim()).ToList();
                        double cpa = 0; //累计 多教师课时

                        if (Config.Check_06_MultiContainSingle && bts.Count == 1 && selected.Count() > 0)
                        {
                            LackRecords.Add(bc, bn, inc[5]);
                            continue;
                        }

                        foreach (var m in selected)
                        {
                            if (Config.Check_02_LessonNameDiff && m[cni] != bn)
                            {
                                LackRecords.Add(bc, bn, inc[1]);
                                break;
                            }

                            if (Config.Check_03_TotalPeriodDiff)
                            {
                                double cp = m[cpi].As<double>();
                                if (cp != bp)
                                {
                                    LackRecords.Add(bc, bn, $"{inc[2]}，开课情况表 中的课时为 {bp}，而 多教师开课表 中为 {cp}");
                                    break;
                                }
                            }

                            var ct = m[cti];
                            if (bts.Contains(ct))
                            {
                                bts.Remove(ct);
                                cpa += m[ctpi].As<double>();
                            }
                            else if (Config.Check_04_TeachersDiff)
                            {
                                LackRecords.Add(bc, bn, $"{inc[3]}，多教师开课表 中出现了未在 开课情况表 中列出的教师姓名（{ct}），或该教师姓名出现了多次");
                            }

                            var ci = m[cii];
                            if (bis.Contains(ci))
                            {
                                bis.Remove(ci);
                            }
                            else if (Config.Check_07_TeacherIDsDiff)
                            {
                                LackRecords.Add(bc, bn, $"{inc[6]}，多教师开课表 中出现了未在 开课情况表 中列出的教师工号（{ci}），或该教师工号出现了多次");
                            }
                        }
                        if (Config.Check_04_TeachersDiff && bts.Count > 0)
                        {
                            LackRecords.Add(bc, bn, $"{inc[3]}，开课情况表 中的教师姓名并未全部在 多教师开课表 中列出");
                            continue;
                        }

                        if (Config.Check_07_TeacherIDsDiff && bis.Count > 0)
                        {
                            LackRecords.Add(bc, bn, $"{inc[6]}，开课情况表 中的教师工号并未全部在 多教师开课表 中列出");
                            continue;
                        }

                        if (Config.Check_05_PeriodSumMiss && bp != cpa)
                        {
                            LackRecords.Add(bc, bn, $"{inc[4]}，总课时为 {bp}，而 累加的教师课时为 {cpa}");
                            continue;
                        }
                    }


                    LackRecords.UpdateDg(DgLack, TcLack);
                }
                else
                {
                    MessageBox.Show("无法执行，数据尚未有效加载！");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Logger.Write($"Err on Exec:{ex.Message}");
            }
        }

        public void EditConfig()
        {
            new ConfigWindow(Config) { Owner = this }.ShowDialog();
            silo.Store("default", Config);
            silo.Save(configpath);
        }

        private int GetColIndex(RecordCollection collection, string colName)
        {
            var i = collection.PropNames.IndexOf(s => s == colName);
            if (i == -1)
            {
                throw new Exception("缺少列定义：" + colName);
            }
            else
            {
                return i;
            }
        }

        public void Help()
        {
            try
            {
                Process.Start("https://gitee.com/heroius/neu-tab-diff-periods/wikis");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Logger.Write($"Err on Help:{ex.Message}");
            }
        }

    }
}
